﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using WPNextTools.NFactory;
using System.Diagnostics;

namespace WPNextTools.NBase
{
    public class NListSource : DisposableObject,IWeakEventListener
    {
        #region Fields
        public const string CollectionChangedEventName = "CollectionChanged";
        private const uint SettingSourceStateKey = 4u;
        private const uint RefreshingStateKey = 8u;
        internal static readonly object UnsetObject = new object();
        private IEnumerable sourceCollection;
        private List<IDataSourceItem> items;
        private IDataSourceItemFactory itemFactory;
        #endregion

        #region Event
        private WeakEeventHandler<NotifyCollectionChangedEventArgs> collectionChangedHandler;

        private NotifyCollectionChangedEventHandler collectionChangedEvent;

        public event NotifyCollectionChangedEventHandler CollectionChanged
        {
            add
            {
                this.collectionChangedEvent = (NotifyCollectionChangedEventHandler)Delegate.Combine(this.collectionChangedEvent, value);
            }
            remove
            {
                this.collectionChangedEvent = (NotifyCollectionChangedEventHandler)Delegate.Remove(this.collectionChangedEvent, value);
            }
        }
        #endregion

        #region Constructor
        public NListSource()
        {
            this.itemFactory = new DataSourceItemFactory();
            this.items = new List<IDataSourceItem>();
        }

        ~NListSource()
        {
            if (this.collectionChangedHandler != null)
            {
                collectionChangedHandler.Unsubscribe();
                collectionChangedHandler = null;
            }
        }
        #endregion

        #region Properties
        public IEnumerable SourceCollection
        {
            get { return sourceCollection; }
            set
            {
                if (this.sourceCollection == value)
                {
                    return;
                }
                this.SetSource(value);
            }
        }

        public List<IDataSourceItem> ListSourceItems
        {
            get
            {
                return this.items;
            }
        }

        protected virtual IEnumerable DataItemsSource
        {
            get
            {
                return this.sourceCollection;
            }
        }

        public IDataSourceItemFactory ItemFactory
        {
            get
            {
                return this.itemFactory;
            }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException();
                }
                this.itemFactory = value;
                this.Refresh();
            }
        }

        #region ItemsCount
        public int Count
        {
            get { return this.items.Count; }
        }
        #endregion

        #endregion

        #region Source
        /// <summary>
        /// 设置数据源
        /// </summary>
        private void SetSource(IEnumerable value)
        {
            base[SettingSourceStateKey] = true;
            this.AttachData(value);
            base[SettingSourceStateKey] = false;
        }
        #endregion
        
        #region Attach
        /// <summary>
        /// 添加数据集合
        /// </summary>
        /// <param name="data"></param>
        private void AttachData(IEnumerable data)
        {
            if (this.sourceCollection != null)
            {
                this.DetachData(this.sourceCollection);
            }
            this.sourceCollection = data;
            if (this.sourceCollection != null)
            {
                INotifyCollectionChanged notifyCollectionChanged = data as INotifyCollectionChanged;
                if (notifyCollectionChanged != null)
                {
                    this.collectionChangedHandler = new WeakEeventHandler<NotifyCollectionChangedEventArgs>(notifyCollectionChanged, this, CollectionChangedEventName);
                }
            }
            this.Refresh();
        }
        #endregion

        #region Detach
        /// <summary>
        /// 解除事件的注册
        /// </summary>
        /// <param name="data"></param>
        private void DetachData(IEnumerable data)
        {
            if (collectionChangedHandler != null)
            {
                collectionChangedHandler.Unsubscribe();
                collectionChangedHandler = null;
            }
        }
        #endregion

        #region Refresh
        public void Refresh()
        {
            if (!base.IsSuspended && !base[RefreshingStateKey])
            {
                base[RefreshingStateKey] = true;
                this.RefreshOverride();
                base[RefreshingStateKey] = false;
            }
        }

        protected virtual void RefreshOverride()
        {
            this.items.Clear();
            this.BuildDataItems();
            this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }
        #endregion

        #region GenerateDataSourceItem
        /// <summary>
        /// 根据信息生成承载信息的DataSourceItem
        /// </summary>
        /// <param name="dataItem"></param>
        /// <param name="newCurrentItem"></param>
        /// <returns></returns>
        internal IDataSourceItem CreateNewDataSourceItem(object dataItem)
        {
            return this.itemFactory.CreateItem(dataItem);
        }
        #endregion

        #region ReceiveEventFromWeakEventHandler
        /// <summary>
        /// 获取事件方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ReceiveEvent(object sender, EventArgs e)
        {
            if (e is NotifyCollectionChangedEventArgs)
            {
                this.OnSourceCollectionChanged(sender, e as NotifyCollectionChangedEventArgs);
                return;
            }
        }
        #endregion

        #region CollectionChanged
        /// <summary>
        /// 开始添加删除重置操作
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            this.itemFactory.OnOwningListSourceCollectionChanged(e);
            if (!base.IsSuspended)
            {
                this.SourceCollectionChangedOverride(e);
            }
        }
        /// <summary>
        /// 将对dataitem 的数据操作转换为idatasourceitem的数据操作
        /// </summary>
        /// <param name="e"></param>
        protected virtual void SourceCollectionChangedOverride(NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    this.AddItems(e);
                    this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, this.items[e.NewStartingIndex], e.NewStartingIndex));
                    break;
                case NotifyCollectionChangedAction.Remove:
                    IDataSourceItem removeDataSourceItem = this.items[e.OldStartingIndex];//要删除的sourcitem
                    this.RemoveItems(e);
                    this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removeDataSourceItem, e.OldStartingIndex));
                    break;
                case NotifyCollectionChangedAction.Replace:
                    this.ReplaceItems(e);
                    IDataSourceItem replaceItem = this.items[e.NewStartingIndex];
                    this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, replaceItem, e.NewStartingIndex));
                    break;
                case NotifyCollectionChangedAction.Reset:
                    this.Refresh();
                    break;
                default:
                    break;
            }
        }

        protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (this.collectionChangedEvent != null)
            {
                this.collectionChangedEvent.Invoke(this, e);
            }
        }

        #endregion

        #region BuildDataItems
        internal virtual void BuildDataItems()
        {
            IDataSourceItem previousDataSourceItem = null;
            int num = 0;
            IEnumerable dataItemsSource = this.DataItemsSource;
            if (dataItemsSource != null)
            {
                IEnumerator enumerator = dataItemsSource.GetEnumerator();
                try
                {
                    while (enumerator.MoveNext())
                    {
                        object current = enumerator.Current;
                        IDataSourceItem newDataSourceItem = this.CreateNewDataSourceItem(current);
                        newDataSourceItem.Index = num;

                        if (previousDataSourceItem != null)
                        {
                            newDataSourceItem.Previous = previousDataSourceItem;
                            previousDataSourceItem.Next = newDataSourceItem;
                        }

                        this.items.Add(newDataSourceItem);
                        previousDataSourceItem = newDataSourceItem;
                        num++;
                    }
                }
                finally
                {
                    IDisposable disposable = enumerator as IDisposable;
                    if (disposable != null)
                    {
                        disposable.Dispose();
                    }
                }
            }
        }
        #endregion

        #region AddOrInsertItems
        /// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="e"></param>
        private void AddItems(NotifyCollectionChangedEventArgs e)
        {
            int newStartingIndex = e.NewStartingIndex;
            IDataSourceItem previousDataSourceItem = null;
            if (newStartingIndex > 0)
            {
                previousDataSourceItem = this.items[newStartingIndex - 1];
            }
            for (int i = 0; i < e.NewItems.Count; i++)
            {
                object value = e.NewItems[i];
                IDataSourceItem newDataSourceItem = this.CreateNewDataSourceItem(value);
                newDataSourceItem.Index = newStartingIndex;
                newDataSourceItem.Previous = previousDataSourceItem;
                if (previousDataSourceItem != null)
                {
                    previousDataSourceItem.Next = newDataSourceItem;
                }
                this.items.Insert(newStartingIndex++, newDataSourceItem);
                previousDataSourceItem = newDataSourceItem;
            }
            //重置索引
            this.ShiftIndexes(e.NewStartingIndex + e.NewItems.Count, e.NewItems.Count);
            if (newStartingIndex < this.items.Count)
            {
                IDataSourceItem nextDataSourceItem = this.items[newStartingIndex];
                nextDataSourceItem.Previous = previousDataSourceItem;
                if (previousDataSourceItem != null)
                {
                    previousDataSourceItem.Next = nextDataSourceItem;
                }
            }
        }
        #endregion

        #region ShiftIndex
        private void ShiftIndexes(int start, int offset)
        {
            int count = this.items.Count;
            for (int i = start; i < count; i++)
            {
                this.items[i].Index += offset;
            }
        }
        #endregion

        #region RmoveItems
        /// <summary>
        /// 删除信息
        /// </summary>
        /// <param name="e"></param>
        protected virtual void RemoveItems(NotifyCollectionChangedEventArgs e)
        {
            for (int i = 0; i < e.OldItems.Count; i++)
            {
                IDataSourceItem dataSourceItem = this.items[e.OldStartingIndex];
                dataSourceItem.Previous = null;
                dataSourceItem.Next = null;
                this.items.RemoveAt(e.OldStartingIndex);
            }
            this.ShiftIndexes(e.OldStartingIndex, -e.OldItems.Count);
            IDataSourceItem dataSourceItem2 = null;
            IDataSourceItem dataSourceItem3 = null;
            if (e.OldStartingIndex > 0)
            {
                dataSourceItem2 = this.items[e.OldStartingIndex - 1];
            }
            if (e.OldStartingIndex < this.items.Count)
            {
                dataSourceItem3 = this.items[e.OldStartingIndex];
            }
            if (dataSourceItem3 != null)
            {
                dataSourceItem3.Previous = dataSourceItem2;
            }
            if (dataSourceItem2 != null)
            {
                dataSourceItem2.Next = dataSourceItem3;
            }
        }
        #endregion

        #region ReplaceItems
        protected virtual void ReplaceItems(NotifyCollectionChangedEventArgs e)
        {
            int newStartingIndex = e.NewStartingIndex;
            for (int i = 0; i < e.NewItems.Count; i++)
            {
                IDataSourceItem dataSourceItem = this.items[newStartingIndex++];
                dataSourceItem.ChangeValue(e.NewItems[i]);
            }
        }
        #endregion

        #region DataSourceItemValue
        /// <summary>
        /// 根据信息容器获得信息
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        internal object RequestDataFormItem(DataSourceItem item)
        {
            IList list = this.sourceCollection as IList;
            if (list == null)
            {
                return null;
            }
            if (item.Index < list.Count)
            {
                return list[item.Index];
            }
            return UnsetObject;
        }
        #endregion

      
    }
}
